package cn.gs.util.net;

// @author gs
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ReConnectSocket extends DefaultSocket {

    public ReConnectSocket() {
    }

    public ReConnectSocket(String ip, int port) throws UnknownHostException, IOException {
        this.host = ip;
        this.port = port;
    }

    @Override
    protected void onDisconnect(Throwable th) {
        boolean flag;
        try {
            setSocket(null);
        } catch (Throwable ex) {
            Logger.getLogger(DefaultSocket.class.getName()).log(Level.WARNING, "Disconnect_close_socket", ex);
        }
        if (on != null) {
            flag = on.onDisconnect(th);
        } else {
            flag = true;
        }
        if (flag) {
            connect();
        }
    }
    String host;
    int port;
    DisconnectListener on;

    public void setDisconnectListener(DisconnectListener on) {
        this.on = on;
    }

    public void setSocket(Socket socket) {
        synchronized (readLock) {
            synchronized (writeLock) {
                if (socket != null) {
                    host = socket.getInetAddress().getHostName();
                    port = socket.getPort();
                }
                super.setSocket(socket);
            }
        }
    }

    public void connect(String ip, int port) {
        synchronized (readLock) {
            synchronized (writeLock) {
                this.host = ip;
                this.port = port;
                connect();
            }
        }
    }

    @Override
    public boolean supportReconnect() {
        return true;
    }

    public String localIP() {
        return getSocket() == null ? "UnConnected" : super.localIP();
    }

    public String remoteIP() {
        return getSocket() == null ? "UnConnected" : super.remoteIP();
    }

    private boolean unconnected() {
        return getSocket() == null || getSocket().isClosed();
    }

    private void connect() {
        if (!unconnected()) {
            return;
        }
        synchronized (this) {
            while (unconnected()) {
                synchronized (readLock) {
                    synchronized (writeLock) {
                        try {
                            if (getSocket() == null) {
                                setSocket(new Socket(host, port));
                            } else {
                                getSocket().connect(new InetSocketAddress(host, port));
                            }
                            Logger.getLogger(ReConnectSocket.class.getName()).log(Level.INFO, "{0}<->{1}", new Object[]{localIP(), remoteIP()});
                        } catch (IOException ex) {
                            Logger.getLogger(ReConnectSocket.class.getName()).log(Level.WARNING, null, ex);
                            try {
                                Thread.sleep(5000);
                            } catch (InterruptedException e) {
                                Logger.getLogger(ReConnectSocket.class.getName()).log(Level.SEVERE, null, e);
                            }
                            continue;
                        }
                    }
                }
            }
        }
    }

    @Override
    public void write(String msg) {
        while (true) {
            connect();
            try {
                super.write(msg);
                return;
            } catch (IOException ex) {
            }
        }
    }

    @Override
    public String readLine() {
        while (true) {
            connect();
            try {
                String s = super.readLine();
                return s;
            } catch (IOException ex) {
            }
        }
    }
}
